#ifndef __SUPPORT_H__
#define __SUPPORT_H__

#include <queue>
#include <vector>
#include <string>

#include <cassert>
#include <assert.h>

#include <limits.h>


#include "Image.H"
#include "Util.H"
#include "IO.H"



//putting namespaces in header files might not be the best solution
using namespace std;
using namespace pip;

// Arrays with offsets to 2D neighborhood.
// Taking the first 4 gives 4-neighborhood, taking all gives 8-neighborhood.
static const int dnbx2D[8] = {1, 0,-1, 0, 1, 1,-1,-1};
static const int dnby2D[8] = {0, 1, 0,-1, 1,-1, 1,-1};
// Arrays with offsets to 3D neighborhood.
// Taking the first 6 gives 6-neighborhood, taking first 18 gives 18-neighborhood,
// taking all gives 26 neighborhood.
static const int dnbx3D[26] = {1, 0, 0,-1, 0, 0,   1, 1, 1, 1, 0, 0,-1,-1,-1,-1, 0, 0,   1, 1, 1,-1,-1,-1, 1,-1};
static const int dnby3D[26] = {0, 1, 0, 0,-1, 0,   1,-1, 0, 0, 1, 1, 1,-1, 0, 0,-1,-1,   1,-1, 1, 1, 1,-1,-1,-1};
static const int dnbz3D[26] = {0, 0, 1, 0, 0,-1,   0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1,   1, 1,-1, 1,-1, 1,-1,-1};



class Pixel
{
        private:
            int x, y, z;

        public:
        Pixel(int x = 0, int y = 0, int z = 0) {set(x,y,z);};

        template <class T>
        T get(const Image<T> &im) const {return im(x,y,z);}

        template <class T>
        void set(Image<T> &im,T val) const {im(x,y,z) = val;}

        void get(int &ix, int &iy, int &iz) const {ix=x;iy=y;iz=z;}

		bool negative()  {return (x < 0);}

        void set(int ix, int iy, int iz = 0) {x=ix;y=iy;z=iz;}

		Pixel& operator=(const Pixel &rhs) {if (this != &rhs) { x=rhs.x; y=rhs.y; z=rhs.z; } return *this; }

        template <class T>
        void getNeighbors(const Image<T> &im,vector<Pixel> &v, int n=6) const
        {
                v.clear();
                if(n==4||n==8){//2D
                        for(int i=0; i<n; ++i){
                                Pixel p = *this;
                                p.x+=dnbx2D[i];
                                if(p.x<0 || p.x>=im.dim(0)) continue;
                                p.y+=dnby2D[i];
                                if(p.y<0 || p.y>=im.dim(1)) continue;
                                //if we get here, the position is in the image
                                v.push_back(p);
                        }
                }
                else if(n==6||n==18||n==26){//3D
                        for(int i=0; i<n;++i){
                                Pixel p =*this;
                                p.x+=dnbx3D[i];
                                if(p.x<0 || p.x>=im.dim(0)) continue;
                                p.y+=dnby3D[i];
                                if(p.y<0 || p.y>=im.dim(1)) continue;
                                p.z+=dnbz3D[i];
                                if(p.z<0 || p.z>=im.dim(2)) continue;
                                v.push_back(p);
                        }
                }
                else
                assert(false);//illegal value of n
        }

};


template <class T>
pip::Image<unsigned char> convertAllToUnsignedChar(const pip::Image<T> &input)
{
  pip::Image<unsigned char> output;
  T min, max;
  getMinMaxImage(input, min, max);

  output.resize(input.dimension());

  if (min == max) {
    output.fill(128);
    return output;
  }
  
  float scale( float(numeric_limits<unsigned char>::max()) / (max - min));
  //std::cout << int(max - min) << "   \n";
  //std::cout << int(T(numeric_limits<unsigned char>::max())) << "   \n";
  //std::cout << scale << "   \n";
  for (int z = 0; z < input.dim(2); ++z) {
    for (int y = 0; y < input.dim(1); ++y) {
      for (int x = 0; x < input.dim(0); ++x) {
		  //std::cout << int(unsigned char((scale * (input(x, y, z) - min))))<< "   ";
        output(x, y, z) = (unsigned char)(scale * (input(x, y, z) - min));
      }
    }
  }
  return output;
}


//template <typename T>
void getHistogram(const Image<unsigned char> &image, vector<unsigned int> &vHist, bool cum=false)
{
    if (image.empty()) return;
      
    vHist.clear();
    vHist.resize(256);
    
    for (int y = 0; y < image.dim(1); ++y) {
            for (int x = 0; x < image.dim(0); ++x) {
                    vHist[image(x, y)]++;
            }
    }
	if(cum){
		for (unsigned int i = 1; i < vHist.size(); ++i){
            vHist[i] = vHist[i - 1] + vHist[i];
		}
	}
}


template <typename T>
void FIsort(const pip::Image<T> &image,std::vector<std::vector<Pixel> > &levels){
	assert(image.dim(0)-1);

	int colors(numeric_limits<T>::max()+1);
	vector<unsigned int> cumulative_histogram(colors); 
	levels.resize(colors);
	
	getHistogram(image,cumulative_histogram,true);
	
	for(int z=0; z<image.dim(2);++z){
		for(int y=0; y<image.dim(1);++y){
			for(int x=0; x<image.dim(0);++x){
				levels[image(x,y,z)].push_back(Pixel(x,y,z));
			}
		}
	}
}






#endif